package com.ljs.springloopdependencies.resolveProcess;

import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.beans.factory.FactoryBean;

import java.util.Map;
import java.util.Set;

/**
 * 模拟过程
 * 读取配置文件或注解元数据生成BeanDefinition
 * 根据BeanDefinition实例化Bean
 * 填充Bean的属性字段，如果存在属性是其他Bean，并且还未实例化，需要实例化该Bean，完成填充
 * 初始化Bean
 */
public class ResolveProcess {
     Map<String,Object> singletonObjects;//保存已经初始化的单例的map,key是beanName
    //下面的定义就是为了解决循环依赖
    Map<String, FactoryBean<?> > singletonFactories; //创建Bean的工厂map，ObjectFactory是个接口，只有一个方法getObject()，返回Bean
    Map<String, Object> earlySingletonObjects;//保存还未装配属性的Bean
    Set<String> singletonsCurrentlyInCreation;//保存正在创建过程中的Bean
    public Object getBean(String beanName){
        Object singletonObject = null;
        //先从缓存中获取，这里是从已经初始化话的bean
        if (singletonFactories.get(beanName)!=null) {
            singletonObject=  singletonFactories.get(beanName);
        }
        //2.如果当前bean正在创建过程中，其实也就是存在循环依赖，不然singletonsCurrentlyInCreation不会包含			beanName
        if(singletonsCurrentlyInCreation.contains(beanName)){
            if (earlySingletonObjects.get(beanName)==null){
                //去实例化但未装配属性的bean结合中获取
               // singletonObject = singletonFactory.getObject();//去对象创建工厂中获取
                //将这个bean对象存入还未装配中去
                earlySingletonObjects.put(beanName, singletonObject);
                //再在缓存删除这个对象
                singletonFactories.remove(beanName);
            }

        }

        //如果缓存不存在
        if(singletonObject==null){
            //开始实例化
            singletonsCurrentlyInCreation.add(beanName);
           // singletonObject= instantiation(beanName);  //伪代码，没有具体实现,假设创建了Bean的实例
            //将创建bean的工厂缓存，其实通过getObject方法返回的就是上面刚刚创建的singletonObject对象，			Spring之所以这么处理，而不是直接缓存到earlySingletonObjects集合，因为在实际执行					getObject方法是，可以进行扩展，用户可以定制getObject的行为。
           // singletonFactories.put(beanName, beanName-> return singletonObject);
            earlySingletonObjects.remove(beanName);

            //装配bean属性，这里对于还未实例化的Bean引用会递归调用getBean方法开始创建，这是理解循环依赖的关键
           // populateBean(singletonObject);//伪代码，没有具体实现,装配Bean的属性

            //bean属性装配完毕，将正在创建的beanName移除
            singletonsCurrentlyInCreation.remove(beanName);
            singletonObjects.put(beanName, singletonObject);//加入到singletonObjects
            singletonFactories.remove(beanName);
            earlySingletonObjects.remove(beanName);

           // initial(singletonObject);//初始化bean

        }
        return singletonObject;
    }
}
